
#pragma once

#include <algorithm>
#include "OgreMath/OgreVector3.h"
#include "Ray.h"

struct AABB
{
	Ogre::Vector3 min, max;
	AABB() {}
	AABB(const Ogre::Vector3 &_min, const Ogre::Vector3 &_max) : min(_min), max(_max) {}

	/// Merge constructor
	AABB(const AABB &aabb1, const AABB &aabb2)
	{
		float epsilon = 0.001f;
		min.x = std::min(aabb1.min.x, aabb2.min.x);
		min.y = std::min(aabb1.min.y, aabb2.min.y);
		min.z = std::min(aabb1.min.z, aabb2.min.z);
		max.x = std::max(aabb1.max.x, aabb2.max.x);
		max.y = std::max(aabb1.max.y, aabb2.max.y);
		max.z = std::max(aabb1.max.z, aabb2.max.z);
	}

	/// Sphere constructor
	AABB(const Ogre::Vector3 &sphereCenter, float sphereRadius)
	{
		min = sphereCenter - Ogre::Vector3(sphereRadius, sphereRadius, sphereRadius);
		max = sphereCenter + Ogre::Vector3(sphereRadius, sphereRadius, sphereRadius);
	}

	/// Triangle constructor
	AABB(const Ogre::Vector3 &p1, const Ogre::Vector3 &p2, const Ogre::Vector3 &p3)
	{
		min.x = std::min(p1.x, p2.x);
		min.x = std::min(min.x, p3.x);
		min.y = std::min(p1.y, p2.y);
		min.y = std::min(min.y, p3.y);
		min.z = std::min(p1.z, p2.z);
		min.z = std::min(min.z, p3.z);

		max.x = std::max(p1.x, p2.x);
		max.x = std::max(max.x, p3.x);
		max.y = std::max(p1.y, p2.y);
		max.y = std::max(max.y, p3.y);
		max.z = std::max(p1.z, p2.z);
		max.z = std::max(max.z, p3.z);
	}

	__forceinline bool rayIntersect(const Ray& ray, float tNear, float tFar) const
	{
		return ray.intersectAABB(&min, tNear, tFar);
	}
	__forceinline bool rayIntersect(const Ray& ray) const
	{
		return ray.intersectAABB(&min);
	}

	__forceinline Ogre::Vector3 getCenter() const
	{
		return (min + max) * 0.5f;
	}

	__forceinline const Ogre::Vector3& getMin() const
	{
		return min;
	}

	__forceinline const Ogre::Vector3& getMax() const
	{
		return max;
	}
};